/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package be.fedict.barth.signer;

import java.io.IOException;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.ocsp.OCSPResponse;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.ocsp.CertificateID;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.cert.ocsp.OCSPReq;
import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;

/**
 *
 * @author hanssens_bart
 */
public class OCSPChecker {
    private static final String MIME_REQ = "application/ocsp-request";
    private static final String MIME_RESP = "application/ocsp-response";
        
    private URL getOCSPUrl(X509Certificate cert) throws IOException {
        URL url = null;
        byte[] b = cert.getExtensionValue(Extension.authorityInfoAccess.getId());
        ASN1Primitive authInfo = JcaX509ExtensionUtils.parseExtensionValue(b);
        AuthorityInformationAccess access = AuthorityInformationAccess.getInstance(authInfo);
    
        for (AccessDescription desc : access.getAccessDescriptions()) {
            if (desc.getAccessMethod().equals(X509ObjectIdentifiers.id_ad_ocsp)) {
                url = new URL(desc.getAccessLocation().getName().toString());
            }
        }
        return url;
    }
    
    private X509Certificate getIssuerCert(X509Certificate cert, X509Certificate[] chain) throws IOException {
        X509Certificate issuer = null;
        
        for (X509Certificate c : chain) {
            if (c.getSubjectX500Principal().equals(cert.getIssuerX500Principal())) {
                issuer = c;
            }
        }
        
        return issuer;
    }
   
    private CertificateID getCertificateID(X509Certificate cert, X509Certificate[] chain) throws NoSuchAlgorithmException, NoSuchProviderException, IOException, OperatorCreationException, OCSPException, CertificateEncodingException {
        AlgorithmIdentifier sha1 = new AlgorithmIdentifier("1.3.14.3.2.26");
        
        X509Certificate issuer = getIssuerCert(cert, chain);
        BigInteger serial = cert.getSerialNumber();
        
        DigestCalculatorProvider digester = new BcDigestCalculatorProvider();
        return new CertificateID(digester.get(sha1), 
                new X509CertificateHolder(issuer.getEncoded()), serial);
    }
    
    public OCSPResponse check(X509Certificate cert, X509Certificate[] chain) throws CertificateEncodingException, IOException, NoSuchAlgorithmException, NoSuchProviderException, OCSPException, OperatorCreationException {
        URL url = getOCSPUrl(cert);

        OCSPReqBuilder reqBuilder = new OCSPReqBuilder();
        reqBuilder.addRequest(getCertificateID(cert, chain));
        
        ASN1Integer nonce = new ASN1Integer(Calendar.getInstance().getTimeInMillis());
        
        ExtensionsGenerator gen = new ExtensionsGenerator();
        gen.addExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, nonce);
        reqBuilder.setRequestExtensions(gen.generate());
        
        OCSPReq req = reqBuilder.build();
        byte b[] = req.getEncoded();
            
        HttpURLConnection conn = Util.Post(url, MIME_REQ, MIME_RESP, b);
        
        OCSPResp resp = new OCSPResp(conn.getInputStream());
        conn.disconnect();

        return resp.toASN1Structure();
    }
    
    public OCSPChecker() {
        
    }
}
